﻿using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RuoVea.DynamicWebApi;
using RuoVea.ExCache;
using RuoVea.ExDto;
using RuoVea.ExEnum;
using RuoVea.ExSugar;
using RuoVea.ExSugar.Entity;
using RuoVea.ExUtil;
using RuoVea.OmiApi.Dict.Entitys;
using RuoVea.OmiApi.Dict.Language;
using RuoVea.OmiApi.Dict.Service.Dto;

namespace RuoVea.OmiApi.Dict.Service;
/// <summary>
/// 字典值服务 🔷
/// </summary>
[ApiExplorerSettings(GroupName = "system")]
public class SysDictValueService : IApplicationService
{
    private readonly SugarRepository<SysDictValue> _thisRepository;
    private readonly SysDictValueValidator _sysDictValueValidator;

    /// <summary>
    /// 字典值服务
    /// </summary>
    /// <param name="thisRepository"></param>
    /// <param name="sysDictValueValidator"></param>
    public SysDictValueService(SugarRepository<SysDictValue> thisRepository, SysDictValueValidator sysDictValueValidator)
    {
        _thisRepository = thisRepository;
        _sysDictValueValidator = sysDictValueValidator;
    }

    /// <summary>
    /// 分页查询字典值🔹
    /// </summary>
    /// <param name="data">查询参数</param>
    /// <returns>分页结果</returns>
    public virtual async Task<PageResult<SysDictValueDto>> GetPagesAsync([FromQuery] SysDictValueParam data)
    {
        // 规范化编码参数（转换为大写）
        if (!string.IsNullOrEmpty(data.Code))
        {
            data.Code = data.Code.Trim().ToUpper();
        }

        var code = !string.IsNullOrEmpty(data.Code?.Trim());
        var value = !string.IsNullOrEmpty(data.Value?.Trim());

        var typeId = data?.TypeId != null;
        var dictDatas = await _thisRepository.AsQueryable()
                              .Where(u => u.IsDelete == IsDelete.N)
                              .WhereIF(typeId, u => u.TypeId == data.TypeId)
                              .WhereIF(code, u => u.Code.Contains(data.Code))
                              .WhereIF(value, u => u.Value.Contains(data.Value))
                              .OrderBy(u => u.Sort)
                              .ToPageAsync<SysDictValue, SysDictValueDto>(data.PageNo, data.PageSize);
        return dictDatas;
    }

    /// <summary>
    /// 根据ID获取字典值详情🔹
    /// </summary>
    /// <param name="data">ID参数</param>
    /// <returns>字典值详情</returns>
    public virtual async Task<SysDictValueDto> GetDataAsync(EntityBaseId data)
    {
        var model = await _thisRepository.AsQueryable().Where(x => x.IsDelete == ExEnum.IsDelete.N && x.Id == data.Id).FirstAsync();
        return model.Adapt<SysDictValueDto>();
    }

    /// <summary>
    /// 根据字典类型编码获取字典值列表🔹
    /// </summary>
    /// <param name="typeCode"> 字典类型编码</param>
    /// <returns>字典值详情</returns>
    public virtual async Task<List<SysDictValueDto>> GetListAsync(string typeCode)
    { 
        // 规范化编码参数（转换为大写）
        if (!string.IsNullOrEmpty(typeCode))
            typeCode = typeCode.Trim().ToUpper();

        var model = await _thisRepository
            .AsQueryable()
            .Where(x => x.IsDelete == IsDelete.N && x.TypeCode == typeCode)
            .ToListAsync();
        return model.Adapt<List<SysDictValueDto>>();
    }

    /// <summary>
    /// 根据字典类型编码获取字典值列表🔹
    /// </summary>
    /// <param name="typeCodes">字典类型编码列表</param>
    /// <returns>字典值详情</returns>
    public virtual async Task<List<SysDictValueDto>> GetListsAsync(List<string> typeCodes)
    {
        // 规范化编码参数（转换为大写）
        if (typeCodes != null && typeCodes.Any())
        {
            typeCodes = typeCodes.Where(x => !string.IsNullOrEmpty(x))
                                .Select(x => x.Trim().ToUpper())
                                .ToList();
        }
        else
        {
            return new List<SysDictValueDto>();
        }

        var model = await _thisRepository
            .AsQueryable()
            .Where(x => x.IsDelete == IsDelete.N && typeCodes.Contains(x.TypeCode))
            .ToListAsync();
        return model.Adapt<List<SysDictValueDto>>();
    }

    /// <summary>
    /// 根据字典类型编码获取字典值列表🔹
    /// </summary>
    /// <param name="typeCodes">字典类型编码列表</param>
    /// <returns>按字典类型分组的字典值详情</returns>
    public virtual async Task<Dictionary<string, List<SysDictValueDto>>> GetGroupListAsync(List<string> typeCodes)
    {
        // 规范化编码参数（转换为大写）
        if (typeCodes != null && typeCodes.Any())
        {
            typeCodes = typeCodes.Where(x => !string.IsNullOrEmpty(x))
                                .Select(x => x.Trim().ToUpper())
                                .ToList();
        }
        else
        {
            return new Dictionary<string, List<SysDictValueDto>>();
        }

        var model = await _thisRepository
            .AsQueryable()
            .Where(x => x.IsDelete == IsDelete.N && typeCodes.Contains(x.TypeCode))
            .ToListAsync();

        // 按 TypeCode 分组并转换为字典
        var result = model.GroupBy(x => x.TypeCode)
                         .ToDictionary(
                             g => g.Key,
                             g => g.Adapt<List<SysDictValueDto>>()
                         );

        // 确保所有请求的 typeCodes 都在字典中有对应的键（即使是空列表）
        foreach (var typeCode in typeCodes)
        {
            if (!result.ContainsKey(typeCode))
            {
                result[typeCode] = new List<SysDictValueDto>();
            }
        }

        return result;
    }
    /// <summary>
    /// 验证 value 格式
    /// </summary>
    /// <param name="tagType"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public virtual bool GetValidateValue(string tagType, string value)
    {
        if (string.IsNullOrWhiteSpace(tagType)) return false;

        // 验证 value 格式
        var valueResult = _sysDictValueValidator.ValidateValueFormat(tagType, value);
        if (!valueResult.IsValid)
            throw new ArgumentException(valueResult.ErrorMessage);
        return valueResult.IsValid;
    }

    /// <summary>
    /// 验证 extData（只在特殊类型时验证）
    /// </summary>
    /// <param name="tagType"></param>
    /// <param name="extData"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public virtual bool GetValidateExtData(string tagType, string extData)
    {
        if (string.IsNullOrWhiteSpace(tagType)) return false;

        // 验证 value 格式
        var valueResult = _sysDictValueValidator.ValidateExtData(tagType, extData);
        if (!valueResult.IsValid)
            throw new ArgumentException(valueResult.ErrorMessage);
        return valueResult.IsValid;
    }


    /// <summary>
    /// 新增字典值🔹
    /// </summary>
    /// <param name="data">字典值数据</param>
    /// <returns>操作结果</returns>
    public virtual async Task<bool> AddDataAsync(SysDictValueDto data)
    {
        // 规范化编码（去除空格）
        data.Code = data.Code?.Trim();

        // 校验编码格式
        if (!ValidateDictValueCodeFormat(data.Code, out string errorMessage))
        {
            throw new ArgumentException(errorMessage);
        }

        // 验证 value 格式
        GetValidateValue(data.TagType, data.Value);
        // 验证 extData（只在特殊类型时验证）
        GetValidateExtData(data.TagType, data.ExtData);

        // 检查同一类型下编码或值是否重复
        var isExist = await _thisRepository.IsAnyAsync(u => (u.Code == data.Code || u.Value == data.Value) && u.TypeId == data.TypeId);

        if (isExist) throw new ArgumentException(i18n.error_message_dict_value_exists);

        var dictData = data.Adapt<SysDictValue>();

        return await _thisRepository.InsertAsync(dictData);
    }

    /// <summary>
    /// 更新字典值🔹
    /// </summary>
    /// <param name="data">字典值数据</param>
    /// <returns></returns>
    public virtual async Task UpdateDataAsync(SysDictValueDto data)
    {
        // 规范化编码（去除空格）
        data.Code = data.Code?.Trim();

        // 校验编码格式
        if (!ValidateDictValueCodeFormat(data.Code, out string errorMessage))
        {
            throw new ArgumentException(errorMessage);
        }

        // 验证 value 格式
        GetValidateValue(data.TagType, data.Value);
        // 验证 extData（只在特殊类型时验证）
        GetValidateExtData(data.TagType, data.ExtData);

        var isExist = await _thisRepository.IsAnyAsync(u => u.Id == data.Id);
        if (!isExist) throw new ArgumentException(i18n.error_message_dict_value_not_found);

        // 排除自己并且判断与其他是否相同
        isExist = await _thisRepository.IsAnyAsync(u => (u.Code == data.Code || u.Value == data.Value) && u.TypeId == data.TypeId && u.Id != data.Id);
        if (isExist) throw new ArgumentException(i18n.error_message_dict_value_exists);

        var dictTypeCode = await _thisRepository.AsQueryable().Where(u => u.TypeId == data.TypeId).Select(u => u.DictType.Code).FirstAsync();
        CacheFactery.Cache.Del($"{CacheConst.KeyDict}{dictTypeCode}");
        var dictData = data.Adapt<SysDictValue>();
        await _thisRepository.UpdateAsync(dictData, ignoreNullValues: true);
    }

    /// <summary>
    /// 删除字典值🔹
    /// </summary>
    /// <param name="data">ID参数</param>
    /// <returns></returns>
    [HttpDelete]
    public virtual async Task DeleteDataAsync([FromBody] EntityBaseId data)
    {
        var dictData = await _thisRepository.GetFirstAsync(u => u.Id == data.Id);
        if (dictData == null) throw new ArgumentException(i18n.error_message_dict_value_not_found);

        var dictTypeCode = await _thisRepository.AsQueryable().Where(u => u.TypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync();
        CacheFactery.Cache.Del($"{CacheConst.KeyDict}{dictTypeCode}");

        if (dictData.IsDelete == IsDelete.Y)
        {
            await _thisRepository.DeleteAsync(x => x.Id == data.Id);
        }
        else
        {
            dictData.IsDelete = IsDelete.Y;
            await _thisRepository.UpdateAsync(dictData);
        }
    }

    /// <summary>
    /// 根据字典类型编码获取字典值列表🔹
    /// </summary>
    /// <returns>字典值列表</returns>
    [HttpGet]
    [AllowAnonymous]
    public async Task<List<SysDictValue>> GetDictDataListByCode(string typeCode)
    {
        var dictDataList = await _thisRepository.Context.Queryable<SysDictType>()
                .LeftJoin<SysDictValue>((u, a) => u.Id == a.TypeId)
                .Where((u, a) => u.Code == typeCode && u.IsDisable == YesOrNot.N && a.IsDisable == YesOrNot.N)
                .OrderBy((u, a) => new { a.Sort, a.Code })
                .Select((u, a) => a).ToListAsync();
        return dictDataList;
    }

    /// <summary>
    /// 根据字典类型编码获取字典值列表🔹
    /// </summary>
    /// <returns>字典值列表</returns>
    [HttpGet]
    [AllowAnonymous]
    public async Task<List<SysDictValue>> GetDictDataListByCodeCache(string typeCode)
    {
        var dictDataList = CacheFactery.Cache.Read<List<SysDictValue>>($"{CacheConst.KeyDict}{typeCode}");
        if (dictDataList == null)
        {
            dictDataList = await _thisRepository.Context.Queryable<SysDictType>()
                .LeftJoin<SysDictValue>((u, a) => u.Id == a.TypeId)
                .Where((u, a) => u.Code == typeCode && u.IsDisable == YesOrNot.N && a.IsDisable == YesOrNot.N)
                .OrderBy((u, a) => new { a.Sort, a.Code })
                .Select((u, a) => a).ToListAsync();
            CacheFactery.Cache.Write($"{CacheConst.KeyDict}{typeCode}", dictDataList);
        }
        return dictDataList;
    }

    /// <summary>
    /// 更新字典值状态🔹
    /// </summary>
    /// <param name="data">状态参数</param>
    /// <returns></returns>
    [HttpPut]
    public async Task ChangeStatus(ChageStateDictValueInput data)
    {
        var dictData = await _thisRepository.GetFirstAsync(u => u.Id == data.Id && u.IsDelete == IsDelete.N);
        if (dictData == null) throw new ArgumentException(i18n.error_message_dict_value_not_found);

        if (!data.IsDisable.IsDefined<YesOrNot>())
            throw new ArgumentException(i18n.error_message_invalid_status);

        dictData.IsDisable = data.IsDisable;
        await _thisRepository.UpdateAsync(dictData);
    }

    /// <summary>
    /// 根据字典类型ID获取字典值列表
    /// </summary>
    /// <param name="dictTypeId">字典类型ID</param>
    /// <returns>字典值列表</returns>
    [NonAction]
    public async Task<List<SysDictValue>> GetDictValueListByDictTypeId(long dictTypeId)
    {
        var dictType = await _thisRepository.ChangeRepository<SugarRepository<SysDictType>>().GetByIdAsync(dictTypeId);
        var dictDataList = await _thisRepository.AsQueryable()
                .Where(u => u.TypeId == dictTypeId).OrderBy(u => new { u.Sort, u.Code }).ToListAsync();
        return dictDataList;
    }

    /// <summary>
    /// 根据字典类型ID获取字典值列表
    /// </summary>
    /// <param name="dictTypeId">字典类型ID</param>
    /// <returns>字典值列表</returns>
    [NonAction]
    public async Task<List<SysDictValue>> GetDictValueListByDictTypeIdCache(long dictTypeId)
    {
        var dictType = await _thisRepository.ChangeRepository<SugarRepository<SysDictType>>().GetByIdAsync(dictTypeId);
        var dictDataList = CacheFactery.Cache.Read<List<SysDictValue>>($"{CacheConst.KeyDict}{dictTypeId}");

        if (dictDataList == null)
        {
            dictDataList = await _thisRepository.AsQueryable()
                .Where(u => u.TypeId == dictTypeId).OrderBy(u => new { u.Sort, u.Code }).ToListAsync();
            CacheFactery.Cache.Write($"{CacheConst.KeyDict}{dictType.Code}", dictDataList);
        }
        return dictDataList;
    }

    /// <summary>
    /// 根据字典类型ID删除字典值
    /// </summary>
    /// <param name="dictTypeId">字典类型ID</param>
    [NonAction]
    public async Task DeleteByTypeId(long dictTypeId)
    {
        var dictTypeCode = await _thisRepository.AsQueryable().Where(u => u.TypeId == dictTypeId).Select(u => u.DictType.Code).FirstAsync();

        if (dictTypeCode != null)
            CacheFactery.Cache.Del($"{CacheConst.KeyDict}{dictTypeCode}");

        await _thisRepository.DeleteAsync(u => u.TypeId == dictTypeId);
    }

    #region New

    /// <summary>
    /// 根据类型编码和值编码获取字典值
    /// </summary>
    /// <param name="typeCode">类型编码</param>
    /// <param name="valueCode">值编码</param>
    /// <returns>字典值</returns>
    [NonAction]
    public async Task<SysDictValue> GetDictDataByTypeCodeValueCode(string typeCode, string valueCode)
    {
        var dictData = await _thisRepository.Context.Queryable<SysDictType>()
                .LeftJoin<SysDictValue>((u, a) => u.Id == a.TypeId)
                .Where((u, a) => u.Code == typeCode && a.Code == valueCode && u.IsDisable == YesOrNot.N && a.IsDisable == YesOrNot.N)
                .OrderBy((u, a) => new { a.Sort, a.Code })
                .Select((u, a) => a).FirstAsync();
        return dictData;
    }

    /// <summary>
    /// 根据类型编码和值编码获取字典值（带缓存）
    /// </summary>
    /// <param name="typeCode">类型编码</param>
    /// <param name="valueCode">值编码</param>
    /// <returns>字典值</returns>
    [NonAction]
    public async Task<SysDictValue> GetDictDataByTypeCodeValueCodeCaChe(string typeCode, string valueCode)
    {
        var dictData = CacheFactery.Cache.Read<SysDictValue>($"{CacheConst.KeyDict}{typeCode}{valueCode}");
        if (dictData == null)
        {
            dictData = await GetDictDataByTypeCodeValueCode(typeCode, valueCode);
            CacheFactery.Cache.Write($"{CacheConst.KeyDict}{typeCode}{valueCode}", dictData);
        }
        return dictData;
    }

    /// <summary>
    /// 根据组合编码获取字典值
    /// </summary>
    /// <param name="typeValueCode">类型编码:值编码</param>
    /// <returns>字典值</returns>
    [NonAction]
    public async Task<SysDictValue> GetDictValue(string typeValueCode)
    {
        if (typeValueCode.IsNullOrWhiteSpace()) return null;
        string[] code = typeValueCode.Split(":");
        if (code.Count() == 2)
        {
            string typeCode = code.First();
            string valueCode = code.Last();
            return await GetDictDataByTypeCodeValueCode(typeCode, valueCode);
        }
        else
            return null;
    }

    /// <summary>
    /// 根据组合编码获取字典值（带缓存）
    /// </summary>
    /// <param name="typeValueCode">类型编码:值编码</param>
    /// <returns>字典值</returns>
    [NonAction]
    public async Task<SysDictValue> GetDictValueCaChe(string typeValueCode)
    {
        if (typeValueCode.IsNullOrWhiteSpace()) return null;
        string[] code = typeValueCode.Split(":");
        if (code.Count() == 2)
        {
            string typeCode = code.First();
            string valueCode = code.Last();
            return await GetDictDataByTypeCodeValueCodeCaChe(typeCode, valueCode);
        }
        else
            return null;
    }

    #region 根据编码查询字典值🔹
    /// <summary>
    /// 根据编码查询字典值🔹
    /// </summary>
    /// <param name="code">字典值编码</param>
    /// <returns>字典值详情</returns>
    [NonAction]
    public async Task<SysDictValueDto> GetDataByCodeAsync(string code)
    {
        var model = await _thisRepository.AsQueryable().Where(x => x.IsDelete == ExEnum.IsDelete.N && x.Code == code).FirstAsync();
        return model.Adapt<SysDictValueDto>();
    }

    /// <summary>
    /// 根据编码查询字典值（带缓存）🔹
    /// </summary>
    /// <param name="code">字典值编码</param>
    /// <returns>字典值详情</returns>
    [NonAction]
    public async Task<SysDictValueDto> GetDataByCodeCaChe(string code)
    {
        var dictData = CacheFactery.Cache.Read<SysDictValueDto>($"{CacheConst.KeyDict}DictValue:{code}");
        if (dictData == null)
        {
            dictData = await GetDataByCodeAsync(code);
            if (dictData == null) return dictData;
            else
            {
                CacheFactery.Cache.Write($"{CacheConst.KeyDict}DictValue:{code}", dictData);
            }
        }
        return dictData;
    }
    #endregion

    /// <summary>
    /// 校验字典值编码格式
    /// </summary>
    [NonAction]
    public bool ValidateDictValueCodeFormat(string code, out string errorMessage)
    {
        errorMessage = null;

        if (string.IsNullOrWhiteSpace(code))
        {
            errorMessage = i18n.error_message_dict_value_code_empty;
            return false;
        }

        code = code.Trim();

        // 长度限制
        if (code.Length > 50)
        {
            errorMessage = i18n.error_message_dict_value_code_too_long;
            return false;
        }

        // 只允许字母、数字、下划线
        if (!System.Text.RegularExpressions.Regex.IsMatch(code, @"^[a-zA-Z0-9_]+$"))
        {
            errorMessage = i18n.error_message_dict_value_code_invalid_chars;
            return false;
        }

        // 必须以字母开头
        if (!char.IsLetter(code[0]))
        {
            errorMessage = i18n.error_message_dict_value_code_start_with_letter;
            return false;
        }

        return true;
    }
    #endregion
}